package cn.com.oceansoft.framework.kits;


import java.io.File;
import java.io.FileFilter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * Created by zhangxh on 2016/12/14.
 */
public class ClassUtil {
    public static Class loadClass(String classPath,String className){
        addURL(classPath);
        Class clazz= null;
        try {
            clazz = Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return clazz;
    }

    /**
     *
     * @param classPath class文件的父路径或者jar包的路径
     *                  D:/test/hello.class 传D:/test
     *                  D:/test/hello.jar 传D:/test/hello.jar
     *                  jar路径可看做class文件的父路径
     */
    public static void addURL(String classPath){
        File clazzPath = new File(classPath);
        Method method = null;
        try {
            method =URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        boolean accessible = method.isAccessible();
        try {
            if (accessible == false) {
                method.setAccessible(true);
            }
            // 设置类加载器
            URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
            // 将当前类路径加入到类加载器中
            try {
                method.invoke(classLoader, clazzPath.toURI().toURL());
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
        } finally {
            method.setAccessible(accessible);
        }
    }
    /**
     *
     * @param classPath class文件的父路径,D:/java/test
     *                  只能应用在包路径和classpath路径一致的情况
     * @return
     */
    public static List<Class> loadClass(String classPath){
        addURL(classPath);
        File clazzPath = new File(classPath);
        // 记录加载.class文件的数量
        List<Class> list=new ArrayList<>();
        if (clazzPath.exists() && clazzPath.isDirectory()) {
            // 获取classpath路径长度 /D:/java/projects/osc_ue_web-portal/target/classes/
            int clazzPathLen= URLDecoder.decode(ClassUtil.class.getClass().getResource("/").getFile().replaceFirst("/","")).length();
            Stack<File> stack = new Stack<>();
            stack.push(clazzPath);

            // 遍历类路径
            while (stack.isEmpty() == false) {
                File path = stack.pop();
                File[] classFiles = path.listFiles(new FileFilter() {
                    public boolean accept(File pathname) {
                        return pathname.isDirectory() || pathname.getName().endsWith(".class");
                    }
                });
                for (File subFile : classFiles) {
                    if (subFile.isDirectory()) {
                        stack.push(subFile);
                    } else {
                        // 文件名称
                        String className = subFile.getAbsolutePath();
                        className = className.substring(clazzPathLen, className.length() - 6);
                        className = className.replace(File.separatorChar, '.');
                        // 加载Class类
                        try {
                            list.add(Class.forName(className));
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }
                        System.out.println(String.format("读取应用程序类文件[class=%s]", className));
                    }
                }
            }
        }
        return list;
    }
    public static void main(String[] args) throws UnsupportedEncodingException, URISyntaxException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        Class clazz=ClassUtil.loadClass("C:/test","cn.com.oceansoft.modules.Hello");
        Method method=clazz.getDeclaredMethod("say");
        method.invoke(clazz.newInstance());
    }

}
